#include <iostream>

// 如果异常抛出的是对象

#if 0
    class Test
    {
    public:
        Test() { std::cout << "构造函数!\n"; }
        Test(const Test &t){ std::cout << "拷贝构造函数!\n"; }
        ~Test() { std::cout << "析构函数!\n"; }
    };

    void func()
    {
        throw Test(); // 抛出匿名对象
    }

    int main()
    {
        try
        {
            func();
        }
        // 抛出的异常会被catch捕获，捕获的时候传的是对象t，就会发生拷贝
        catch (Test t)
        {
            std::cout << "捕获异常!\n";
        }
        
        return 0;
    }
#endif

#if 0
    class Test
    {
    public:
        Test() { std::cout << "构造函数!\n"; }
        Test(const Test &t){ std::cout << "拷贝构造函数!\n"; }
        ~Test() { std::cout << "析构函数!\n"; }
    };

    // void func() throw(int, char, string) 异常声明：声明这个函数会抛出一个异常（C++17之后正式弃用了，影响美观，11会报警告，03可以用）
    // void func() noexcept 随后又引入了无异常声明：声明当前函数不会抛出异常
    void func() 
    {
        // 栈的解旋：在抛出异常之后，捕获异常之前（函数中的和try代码块的）栈上对象会自动析构
        Test t;  // 在函数中先构建一个对象
        throw Test(); // 抛出匿名对象
    }

    int main()
    {
        try
        {
            // 栈的解旋
            // Test t;
            func();
        }
        // 抛出的对象会在捕获异常之后进行析构，并不是抛出这个匿名对象被接住以后就释放了
        // 所以对象可以传引用
        catch (Test &t)
        {
            std::cout << "捕获异常!\n";
        }

        return 0;
    }
#endif

#if 1
    class Test
    {
    public:
        Test() { std::cout << "构造函数!\n"; }
        Test(const Test &t){ std::cout << "拷贝构造函数!\n"; }
        ~Test() { std::cout << "析构函数!\n"; }
    };

    class Derived : public Test
    {

    };

    void func() 
    {
        throw Derived(); // 抛出子类对象
    }

    int main()
    {
        try
        {
            Test t;
            func();
        }
        // 抛出的是子类对象，可以被父类接收
        // 异常的捕获虽然是严格的类型匹配
        // 但是支持向上转型
        catch (Test &t) 
        {
            std::cout << "捕获异常!\n";
        }

        return 0;
    }
#endif